/*
 *  ppui/MessageBoxContainer.cpp
 *
 *  Copyright 2009 Peter Barth
 *
 *  This file is part of Milkytracker.
 *
 *  Milkytracker is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Milkytracker is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Milkytracker.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "GraphicsAbstract.h"
#include "Button.h"
#include "MessageBoxContainer.h"
#include "Font.h"
#include "BasicTypes.h"
#include "PPUIConfig.h"
#include "Screen.h"
#include "SimpleVector.h"

PPMessageBoxContainer::PPMessageBoxContainer (pp_int32 id, PPScreen* parentScreen, EventListenerInterface* eventListener,
                                              const PPPoint& location, const PPSize& size, const PPString& caption) :
    PPContainer(id, parentScreen, eventListener, location, size),
    caption(caption),
    captured(false)
{
    PPContainer::setColor(PPUIConfig::getInstance()->getColor(PPUIConfig::ColorMessageBoxContainer));

    PPFont* font = PPFont::getFont(PPFont::FONT_SYSTEM);
    captionSize = 2 + 2 * 2 + font->getCharHeight() + 1;

    buttonLocation = location;
    buttonLocation.y += captionSize;
    buttonSize = size;
    buttonSize.height -= captionSize;

    button = new PPButton(-1, NULL, NULL, buttonLocation, buttonSize, false, false, false);
    button->setColor(*PPContainer::color);
}

PPMessageBoxContainer::~PPMessageBoxContainer ()
{
    delete button;
}

void PPMessageBoxContainer::paint(PPGraphicsAbstract* g)
{
    if (!isVisible())
        return;

    PPColor bColor = *color, dColor = *color, vbColor = *color;
    // adjust dark color

    dColor.scaleFixed(32768);
    bColor.scaleFixed(87163);
    vbColor.scaleFixed(131072);

    g->setColor(*color);

    g->setRect(location.x, location.y, location.x + size.width, location.y + captionSize);
    g->fill();

    //g->fill();
    button->paint(g);

    g->setRect(location.x, location.y, location.x + size.width, location.y + size.height);

    g->setColor(bColor);

    g->drawHLine(location.x, location.x + size.width, location.y);
    g->drawVLine(location.y, location.y + size.height, location.x);

    g->drawHLine(location.x + 2, location.x + size.width - 2, location.y + size.height - 3);
    g->drawVLine(location.y + 2, location.y + size.height - 2, location.x + size.width - 3);

    g->setColor(dColor);

    g->drawHLine(location.x + 2, location.x + size.width - 2, location.y + 2);
    g->drawVLine(location.y + 2, location.y + size.height - 2, location.x + 2);

    g->drawHLine(location.x, location.x + size.width, location.y + size.height - 1);
    g->drawVLine(location.y, location.y + size.height, location.x + size.width - 1);

    // seperator
    g->setColor(dColor);

    PPFont* font = PPFont::getFont(PPFont::FONT_SYSTEM);

    g->drawHLine(location.x + 2, location.x + size.width - 3, location.y + captionSize - 1);

    g->setColor(bColor);

    g->drawHLine(location.x + 3, location.x + size.width - 2, location.y + captionSize);

    pp_int32 cx = size.width / 2 - font->getStrWidth(caption) / 2;

    g->setColor(0, 0, 0);

    g->drawString(caption, location.x + cx + 1, location.y + 5);

    g->setColor(PPUIConfig::getInstance()->getColor(PPUIConfig::ColorStaticText));

    g->drawString(caption, location.x + cx, location.y + 4);

    paintControls(g);
}

void PPMessageBoxContainer::setSize(const PPSize& size)
{
    PPContainer::setSize(size);

    buttonSize = size;
    buttonSize.height -= captionSize;

    button->setSize(buttonSize);
}

void PPMessageBoxContainer::setLocation(const PPPoint& location)
{
    PPContainer::setLocation(location);

    buttonLocation = location;
    buttonLocation.y += captionSize;

    button->setLocation(buttonLocation);
}

pp_int32 PPMessageBoxContainer::dispatchEvent(PPEvent* event)
{
    switch (event->getID())
    {
        case eLMouseDown:
            lastCapturePoint = *reinterpret_cast<const PPPoint*>(event->getDataPtr());
            captured = isPointInCaption(lastCapturePoint);
            if (captured)
                return 0;
            break;

        case eLMouseDrag:
            if (handleMove(*reinterpret_cast<const PPPoint*>(event->getDataPtr())))
                return 0;
            break;

        case eLMouseUp:
            if (captured)
            {
                captured = false;
                return 0;
            }
            break;
    }

    return PPContainer::dispatchEvent(event);
}

bool PPMessageBoxContainer::isPointInCaption(const PPPoint& point)
{
    PPSimpleVector<PPControl>& controls = getControls();

    for (pp_int32 i = 0; i < controls.size(); i++)
        if (controls.get(i)->hit(point))
            return false;

    return hit(point);

    //return (point.x >= location.x && point.x <= location.x + size.width &&
    //		point.y >= location.y && point.y <= location.y + captionSize);
}

bool PPMessageBoxContainer::handleMove(PPPoint point)
{
    if (!captured)
        return false;

    const pp_int32 catchBound = 4;
    const pp_int32 dcatchBound = catchBound * 2;

    const pp_int32 width = size.width;
    const pp_int32 height = size.height;

    bool ignorex = (point.x < -(width - dcatchBound)) || (point.x >= parentScreen->getWidth() + (width - dcatchBound));
    bool ignorey = (point.y < -(height - dcatchBound)) || (point.y >= parentScreen->getHeight() + (height - dcatchBound));;

    PPPoint delta(ignorex ? 0 : point.x - lastCapturePoint.x, ignorey ? 0 : point.y - lastCapturePoint.y);

    if (!ignorex)
        lastCapturePoint.x = point.x;
    if (!ignorey)
        lastCapturePoint.y = point.y;

    if (location.x + delta.x < -(width - dcatchBound))
    {
        delta.x += -(width - dcatchBound) - (location.x + delta.x);
    }

    if (location.y + delta.y < -(height - dcatchBound))
    {
        delta.y += -(height - dcatchBound) - (location.y + delta.y);
    }

    if (location.x + delta.x >= parentScreen->getWidth() - dcatchBound)
    {
        delta.x -= (location.x + delta.x) - (parentScreen->getWidth() - dcatchBound);
    }

    if (location.y + delta.y >= parentScreen->getHeight() - dcatchBound)
    {
        delta.y -= (location.y + delta.y) - (parentScreen->getHeight() - dcatchBound);
    }

    move(delta);

    PPPoint buttonPos = button->getLocation();
    buttonPos.x += delta.x;
    buttonPos.y += delta.y;
    button->setLocation(buttonPos);

    parentScreen->paint();

    return true;
}